
/*
Modifications made by: Paul Stelly & Ricardo Colas
Modifications for Project 3:
bool Allocate(BitMap *bitMap, int fileSize);
void Deallocate(BitMap *freeMap);
int ByteToSector(int offset);

Additions for Project 3:
int *singlySectors, *extraSectors, **doublySectors;
int NumDirect2 = NumDirect*2;
int type2Max = SectorSize/sizeof(int)*SectorSize+MaxFileSize;
*/

// filehdr.cc 
//      Routines for managing the disk file header (in UNIX, this
//      would be called the i-node).
//
//      The file header is used to locate where on disk the 
//      file's data is stored.  We implement this as a fixed size
//      table of pointers -- each entry in the table points to the 
//      disk sector containing that portion of the file data
//      (in other words, there are no indirect or doubly indirect 
//      blocks). The table size is chosen so that the file header
//      will be just big enough to fit in one disk sector, 
//
//      Unlike in a real system, we do not keep track of file permissions, 
//      ownership, last modification date, etc., in the file header. 
//
//      A file header can be initialized in two ways:
//         for a new file, by modifying the in-memory data structure
//           to point to the newly allocated data blocks
//         for a file already on disk, by reading the file header from disk
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"

#include "system.h"
#include "filehdr.h"

//----------------------------------------------------------------------
// FileHeader::Allocate
//      Initialize a fresh file header for a newly created file.
//      Allocate data blocks for the file out of the map of free disk blocks.
//      Return FALSE if there are not enough free blocks to accomodate
//      the new file.
//
//      "freeMap" is the bit map of free disk sectors
//      "fileSize" is the bit map of free disk sectors
//----------------------------------------------------------------------

bool
FileHeader::Allocate(BitMap *freeMap, int fileSize)
{ 
    numBytes = fileSize;
    numSectors  = divRoundUp(fileSize, SectorSize);
    //Begin Additions by Paul Stelly and Ricardo Colas
        doublySectors = new int*;
	int numLeft;
        int NumDirect2 = (NumDirect+2)*2;
    int type2Max = SectorSize/sizeof(int)*SectorSize+MaxFileSize - SectorSize;
        //End Additions by Paul Stelly and Ricardo Colas
	printf("type2max is %d, NumDirect2 is %d, MaxFileSize is %d\n", type2Max, NumDirect2, MaxFileSize);
	printf("numSectors is %d, numBytes is %d\n", numSectors, numBytes);
    if (freeMap->NumClear() < numSectors)
        return FALSE;           // not enough space
        
        //Begin Modifications by Paul Stelly and Ricardo Colas
        //Type 1
        if(numBytes <= (int)MaxFileSize)
    {
                for (int i = 0; i < numSectors; i++)
                        dataSectors[i] = freeMap->Find();
        
                return TRUE;
    }
        //Type 2
    else if (numBytes > (int)MaxFileSize && numBytes <= type2Max)
    {	
        singlySectors = new int [NumDirect+2];
		freeMap->Print();
                for(int i = 0; i < NumDirect-1; i++)
                {   
                                dataSectors[i] = freeMap->Find();
		}
		numLeft = numSectors - NumDirect;
		for(int j = 0; j < numLeft; j++)
                {
			singlySectors[j] = freeMap->Find();
                        //*singlySectors = freeMap->Find();
                        //singlySectors++;
                }
		dataSectors[NumDirect-1] = singlySectors[0];
                freeMap->Print();
	delete [] singlySectors;
                return TRUE;
    }
        //Type 3
    else if(numBytes > type2Max)
    {
                
                singlySectors = new int [NumDirect+2];
        	extraSectors = new int[NumDirect+2];

               for(int i = 0; i < NumDirect-2; i++)
                {   
                                dataSectors[i] = freeMap->Find();
		}
                numLeft = numSectors - NumDirect;
		for(int j = 0; j < NumDirect; j++)
                {
			singlySectors[j] = freeMap->Find();
                }
		numLeft = numSectors - NumDirect;
                for(int j = 0; j < numLeft; j++)
                {
			extraSectors[j] = freeMap->Find();
                }
                dataSectors[NumDirect-2] = singlySectors[0];
		dataSectors[NumDirect-1] = extraSectors[0];
                return TRUE;
    }
        return FALSE;
        //End Modifications by Paul Stelly and Ricardo Colas
}

//----------------------------------------------------------------------
// FileHeader::Deallocate
//      De-allocate all the space allocated for data blocks for this file.
//
//      "freeMap" is the bit map of free disk sectors
//----------------------------------------------------------------------

void 
FileHeader::Deallocate(BitMap *freeMap)
{
        int NumDirect2 = NumDirect*2;
	int numLeft;
    int type2Max = SectorSize/sizeof(int)*SectorSize+MaxFileSize-SectorSize;
	
        //Begin Modifications by Paul Stelly and Ricardo Colas
        //Type 1
        if(numBytes <= (int)MaxFileSize)
    {
                for (int i = 0; i < numSectors; i++)
                {
                        ASSERT(freeMap->Test((int) dataSectors[i]));
                        freeMap->Clear((int) dataSectors[i]);
                }
    }
        //Type 2
    else if (numBytes > (int)MaxFileSize && numBytes <= type2Max)
    {
		singlySectors = new int [NumDirect+2];
		freeMap->Print();
                for(int i = 0; i < NumDirect-1; i++)
                {
                                ASSERT(freeMap->Test((int) dataSectors[i]));
                                freeMap->Clear((int) dataSectors[i]);
		}
		numLeft = numSectors - NumDirect;
		for(int j = 0; j < numLeft; j++)
                {
			ASSERT(freeMap->Test(singlySectors[j]));
			freeMap->Clear(singlySectors[j]);
                }
		delete [] singlySectors;
    }
        //Type 3
    else if(numBytes > type2Max)
    {
                
                singlySectors = &dataSectors[NumDirect-1];
                extraSectors = &dataSectors[NumDirect];
                doublySectors = &extraSectors;

                for(int i = 0; i < numSectors; i++)
                {
                        if(i < (int)NumDirect)
                        {
                                ASSERT(freeMap->Test((int) dataSectors[i]));
                                freeMap->Clear((int) dataSectors[i]);
                        }
                        else if(i > (int)NumDirect && i < NumDirect2)
                        {
                                //ASSERT(freeMap->Test(*singlySectors));
                                //freeMap->Clear(*singlySectors);
                                //singlySectors = singlySectors + 1;
								ASSERT(freeMap->Test( *(singlySectors + i) ) );
								freeMap->Clear( *(singlySectors + i) );
                        }
                        else
                        {
                                //ASSERT(freeMap->Test(*extraSectors));
                                //freeMap->Clear(*extraSectors);
                               // extraSectors = extraSectors + 1;
								ASSERT(freeMap->Test( *(extraSectors + i) ) );
								freeMap->Clear( *(extraSectors + i) );
                        }
                }
    }
        //End Modifications by Paul Stelly and Ricardo Colas
}

//----------------------------------------------------------------------
// FileHeader::FetchFrom
//      Fetch contents of file header from disk. 
//
//      "sector" is the disk sector containing the file header
//----------------------------------------------------------------------

void
FileHeader::FetchFrom(int sector)
{
    synchDisk->ReadSector(sector, (char *)this);
}

//----------------------------------------------------------------------
// FileHeader::WriteBack
//      Write the modified contents of the file header back to disk. 
//
//      "sector" is the disk sector to contain the file header
//----------------------------------------------------------------------

void
FileHeader::WriteBack(int sector)
{
    synchDisk->WriteSector(sector, (char *)this); 
}

//----------------------------------------------------------------------
// FileHeader::ByteToSector
//      Return which disk sector is storing a particular byte within the file.
//      This is essentially a translation from a virtual address (the
//      offset in the file) to a physical address (the sector where the
//      data at the offset is stored).
//
//      "offset" is the location within the file of the byte in question
//----------------------------------------------------------------------

//Begin Modications by Paul Stelly and Ricardo Colas
int
FileHeader::ByteToSector(int offset)
{
        int NumDirect2 = NumDirect*2;
    int type2Max = SectorSize/sizeof(int)*SectorSize+MaxFileSize;
	singlySectors = new int [NumDirect+2];
	//printf("offset/sectorsize is %d\n", (offset/SectorSize));
	//printf("offset is %d, (NumDirect*SectorSize) is %d\n", offset, (NumDirect*SectorSize));
	//for(int i = 0; i < NumDirect;i++)
	//	printf("dataSectors[%d] = %d\n", i, dataSectors[i]);
        //Type 1
        if(numBytes <= (int)MaxFileSize)
                return(dataSectors[offset / SectorSize]);
        //Type 2
    else if (numBytes > (int)MaxFileSize && numBytes <= type2Max)
    {			
			singlySectors = new int [NumDirect+2];
                        if(offset < (int)(NumDirect*SectorSize))
			{
				//printf("dataSectors[offset / SectorSize] is %d\n", dataSectors[offset / SectorSize]);
                                return(dataSectors[offset / SectorSize]);
			}
                        else
			{
				offset = offset - ((NumDirect+2)*SectorSize);
                                return(singlySectors[(offset/SectorSize)]);
			}
    }
        //Type 3
    else if(numBytes > type2Max)
    {
                singlySectors = new int [NumDirect+2];
        	extraSectors = new int[NumDirect+2];
		
		if(offset < (int)(NumDirect*SectorSize))
                       return(dataSectors[offset / SectorSize]);
		else if(offset > (int)(NumDirect*SectorSize) && offset < type2Max)
		{
			offset = offset - ((NumDirect+2)*SectorSize);
                        return(singlySectors[(offset/SectorSize)]);
		}
		else
		{
			offset = offset - ((NumDirect+2)*SectorSize);
                        return(extraSectors[(offset/SectorSize)]);
		}
    }
        return -1;
}
//End Modifications by Paul Stelly and Ricardo Colas

//----------------------------------------------------------------------
// FileHeader::FileLength
//      Return the number of bytes in the file.
//----------------------------------------------------------------------

int
FileHeader::FileLength()
{
    return numBytes;
}

//----------------------------------------------------------------------
// FileHeader::Print
//      Print the contents of the file header, and the contents of all
//      the data blocks pointed to by the file header.
//----------------------------------------------------------------------

void
FileHeader::Print()
{
    int i, j, k;
    char *data = new char[SectorSize];

    printf("FileHeader contents.  File size: %d.  File blocks:\n", numBytes);
    for (i = 0; i < numSectors; i++)
        printf("%d ", dataSectors[i]);
    printf("\nFile contents:\n");
    for (i = k = 0; i < numSectors; i++) {
        synchDisk->ReadSector(dataSectors[i], data);
        for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {
            if ('\040' <= data[j] && data[j] <= '\176')   // isprint(data[j])
                printf("%c", data[j]);
            else
                printf("\\%x", (unsigned char)data[j]);
        }
        printf("\n"); 
    }
    delete [] data;
}
